package com.x.provider.customer.controller.rpc;

import com.x.core.constant.Constants;
import com.x.core.utils.ApiAssetUtil;
import com.x.core.utils.BeanUtil;
import com.x.core.web.api.R;
import com.x.core.web.controller.BaseRpcController;
import com.x.core.web.page.PageList;
import com.x.provider.api.customer.enums.CustomerRelationEnum;
import com.x.provider.api.customer.model.dto.customer.*;
import com.x.provider.api.customer.service.CustomerRpcService;
import com.x.provider.customer.configure.CustomerApplicationConfig;
import com.x.provider.customer.enums.SystemRoleNameEnum;
import com.x.provider.customer.factory.dto.CustomerDTOFactory;
import com.x.provider.customer.model.bo.ExternalAuthBO;
import com.x.provider.customer.model.domain.customer.*;
import com.x.provider.customer.service.customer.*;
import com.x.provider.customer.service.customer.authext.ExternalAuthEngine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/rpc/customer")
public class CustomerRpcController extends BaseRpcController implements CustomerRpcService {

    private final CustomerService customerService;
    private final CustomerApplicationConfig applicationConfig;
    private final CustomerRelationService customerRelationService;
    private final CustomerStatService customerStatService;
    private final AuthenticationService authenticationService;
    private final CustomerDTOFactory customerFactory;
    private final CustomerSessionService customerSessionService;
    private final CustomerLevelService customerLevelService;
    private final ExternalAuthEngine externalAuthEngine;
    private final CustomerResumeService customerResumeService;
    private final CustomerResourceService customerResourceService;
    private final CustomerMcService customerMcService;
    private final CustomerVerificationService customerVerificationService;
    private final CustomerResumePreferenceService customerResumePreferenceService;

    public CustomerRpcController(CustomerService customerService,
                                 CustomerApplicationConfig applicationConfig,
                                 CustomerRelationService customerRelationService,
                                 CustomerStatService customerStatService,
                                 AuthenticationService authenticationService,
                                 CustomerDTOFactory customerFactory,
                                 CustomerSessionService customerSessionService,
                                 CustomerLevelService customerLevelService,
                                 ExternalAuthEngine externalAuthEngine,
                                 CustomerResumeService customerResumeService,
                                 CustomerResourceService customerResourceService,
                                 CustomerMcService customerMcService,
                                 CustomerVerificationService customerVerificationService,
                                 CustomerResumePreferenceService customerResumePreferenceService){
        this.customerService = customerService;
        this.applicationConfig = applicationConfig;
        this.customerRelationService = customerRelationService;
        this.customerStatService = customerStatService;
        this.authenticationService = authenticationService;
        this.customerFactory = customerFactory;
        this.customerSessionService = customerSessionService;
        this.customerLevelService = customerLevelService;
        this.externalAuthEngine = externalAuthEngine;
        this.customerResumeService = customerResumeService;
        this.customerResourceService = customerResourceService;
        this.customerMcService = customerMcService;
        this.customerVerificationService = customerVerificationService;
        this.customerResumePreferenceService = customerResumePreferenceService;
    }

    @PostMapping("/login/external")
    @Override
    public R<String> loginExternal(@RequestBody LoginExternalReqDTO loginExternalReqDTO) {
        return R.ok(externalAuthEngine.authenticate(BeanUtil.prepare(loginExternalReqDTO, ExternalAuthBO.class)));
    }

    @PostMapping("/logout")
    @Override
    public R<Void> logout(String token) {
        authenticationService.signOut(token);
        return R.ok();
    }

    @PostMapping("/list")
    @Override
    public R<Map<Long, CustomerDTO>> listCustomer(@RequestBody CustomerListReqDTO listCustomerAO) {
        return R.ok(customerFactory.prepare(listCustomerAO));
    }

    @PostMapping("/authorize")
    @Override
    public R<Long> authorize(@RequestBody CustomerAuthorizeRequestDTO request){
        logger.info("authorize, token:{} path:{}", request.getToken(), request.getPath());
        if (request.getPath().startsWith(Constants.WS_URL_PREFIX)){
            return R.ok(0L);
        }
        long customerId = StringUtils.hasText(request.getToken()) ? authenticationService.getAuthenticatedCustomerId(request.getToken()) : 0;
        if (customerId > 0){
            customerSessionService.saveActiveSession(customerId, request.getIp());
        }
        if (request.getPath().startsWith(Constants.APP_URL_PREFIX)){
            return R.ok(customerId);
        }
        if (applicationConfig.getAuthIgnoreUrls().stream().anyMatch(item -> item.startsWith(request.getPath()) || request.getPath().endsWith(item))){
            return R.ok(customerId);
        }
        List<Role> roles = customerService.listCustomerRole(customerId);
        if (request.getPath().startsWith(Constants.ADMIN_URL_PREFIX)){
            ApiAssetUtil.isTrue(roles.stream().allMatch(item -> item.getSystemName().equals(SystemRoleNameEnum.ADMINISTRATORS.toString())));
        }

        if (request.getPath().startsWith(Constants.APP_URL_PREFIX)){
            ApiAssetUtil.isTrue(roles.stream().allMatch(item -> item.getSystemName().equals(SystemRoleNameEnum.REGISTERED.toString())));
        }
        return R.ok(customerId);
    }

    @PostMapping("/authorize/user/name/update")
    @Override
    public R<Void> customerUserNameUpdate(CustomerUserNameUpdateReqDTO request) {
        customerService.changeUserName(request);
        return R.ok();
    }

    @PostMapping("/follow/list")
    @Override
    public R<List<Long>> listFollow(@RequestParam long customerId) {
        return R.ok(customerRelationService.listFollow(customerId));
    }

    @PostMapping("/simple/list")
    @Override
    public R<Map<Long, CustomerSimpleDTO>> listSimpleCustomer(@RequestBody CustomerListReqDTO customerListReqDTO) {
        return R.ok(customerFactory.prepareSimpleCustomer(customerListReqDTO));
    }

    @PostMapping("/stat/inc")
    @Override
    public R<Void> addCustomerExp(@RequestBody IncCustomerStatRequestDTO incCustomerStatAO) {
        customerStatService.inc(BeanUtil.prepare(incCustomerStatAO, CustomerStat.class));
        return R.ok();
    }

    @GetMapping("/v2/authorize")
    @Override
    public R<Long> authorizeV2(String token, String path, String ip) {
        return authorize(CustomerAuthorizeRequestDTO.builder().token(token).path(path).ip(ip).build());
    }

    @PostMapping("/level/exp/add")
    @Override
    public R<Void> addCustomerExp(@RequestBody CustomerExpAddRequestDTO requestDTO) {
        customerLevelService.addCustomerExp(requestDTO.getCustomerId(), requestDTO.getExp());
        return R.ok();
    }

    @PostMapping("/resume/save")
    @Override
    public R<Long> saveCustomerResume(@RequestBody CustomerResumeSaveReqDTO customerResumeSaveReqDTO) {
        return R.ok(customerResumeService.saveResume(customerResumeSaveReqDTO)) ;
    }

    @PostMapping("/resume/attribute/save")
    @Override
    public R<Void> saveCustomerResumeAttribute(@RequestBody CustomerResumeAttributeSaveReqDTO resumeAttributeReqDTO) {
        log.info("save customer resume attribute, key:{} value:{}", resumeAttributeReqDTO.getKey(), resumeAttributeReqDTO.getValue());
        customerResumeService.setResumeAttribute(resumeAttributeReqDTO);
        customerMcService.onNickNameSave(resumeAttributeReqDTO.getCustomerId(), resumeAttributeReqDTO.getKey(), resumeAttributeReqDTO.getValue());
        return R.ok();
    }

    @PostMapping("/resource/operate")
    @Override
    public R<Long> operateCustomerResource(@RequestBody CustomerResourceOperReqDTO reqDTO) {
        Long result = customerResourceService.operateCustomerResource(reqDTO);
        return R.ok(result);
    }

    @PostMapping("/relation/customer/id")
    @Override
    public R<PageList<CustomerRelationDTO>> listMyCustomerRelation(@RequestBody CustomerRelationMyReqDTO reqDTO) {
        PageList<CustomerRelation> relationList = customerRelationService.listCustomerRelation(reqDTO.getCustomerId(), CustomerRelationEnum.valueOf(reqDTO.getCustomerRelation()),
                reqDTO.getPageDomain());
        if (relationList.isEmptyList()){
            return R.ok(new PageList<>());
        }
        return R.ok(relationList.map(BeanUtil.prepare(relationList.getList(), CustomerRelationDTO.class)));
    }

    @PostMapping("relation/update")
    @Override
    public R<CustomerRelationDTO> updateCustomerRelation(CustomerRelationUpdateDTO reqDTO) {
        CustomerRelation customerRelation = customerRelationService.changeCustomerRelation(reqDTO.getFromCustomerId(), reqDTO.getToCustomerId(), reqDTO.getFollow());
        return R.ok(BeanUtil.prepare(customerRelation, CustomerRelationDTO.class));
    }

    @PostMapping("verification/save")
    @Override
    public R<Void> saveCustomerVerification(@RequestBody CustomerVerificationSaveReqDTO reqDTO) {
        customerVerificationService.save(reqDTO);
        return R.ok();
    }

    @PostMapping("resume/preference/save")
    @Override
    public R<Void> saveCustomerResumePreference(@RequestBody CustomerResumePreferenceSaveReqDTO req) {
        customerResumePreferenceService.save(req);
        return R.ok();
    }

    @PostMapping("/resume/search")
    @Override
    public R<PageList<CustomerResumeDTO>> searchCustomerResume(@RequestBody CustomerResumeSearchReqDTO customerResumeSaveReqDTO) {
        PageList<CustomerResume> entityResult = customerResumeService.listResume(customerResumeSaveReqDTO);
        if (entityResult.isEmptyList()){
            return R.ok(new PageList<>());
        }
        return R.ok(PageList.map(entityResult, BeanUtil.prepare(entityResult.getList(), CustomerResumeDTO.class)));
    }




}
